package com.wowangz.cms.common.mongo;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.DefaultPropertiesPersister;
import org.springframework.util.PropertiesPersister;

import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoException;
import com.mongodb.ServerAddress;
import com.wowangz.cms.common.utils.SpringContextHolder;

@SuppressWarnings("deprecation")
public class MongoDBManager {

	private static final String DEFAULT_ENCODING = "UTF-8";

	private static final Logger logger = LoggerFactory.getLogger(MongoDBManager.class);
	private static MongoDBManager manager = null;
	private static PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();

	public static MongoDBManager getDefaultMongoDBManager() {
		return manager;
	}

	public static void main(String[] args) {
		try {
			MongoDBManager manager = MongoDBManager.getDefaultMongoDBManager();
			manager.getDB("pictrue");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String accessUrl;// 访问地址
	private String attachmentUrl;// 其他附件访问地址

	private String attachmentDBName;// 附件数据库名称

	private MongoClient mongo = null;

	private String mongoConfigFileName;// 配置文件的名称

	private String pictureDBName;// 图片文件数据库名称
	
	private Long pictureSize;
	
	public Long getPictureSize() {
		return pictureSize;
	}
	
	public void setPictureSize(Long pictureSize) {
		this.pictureSize = pictureSize;
	}

	public String getAccessUrl() {
		return accessUrl;
	}

	public String getAttachmentDBName() {
		return attachmentDBName;
	}
	
	private Integer fileMaxSize;

	public String getAttachmentUrl() {
		return attachmentUrl;
	}

	public void setAttachmentUrl(String attachmentUrl) {
		this.attachmentUrl = attachmentUrl;
	}

	public Integer getFileMaxSize() {
		return fileMaxSize;
	}
	
	public void setFileMaxSize(Integer fileMaxSize) {
		this.fileMaxSize = fileMaxSize;
	}
	
	/**
	 * 根据名称获取DB，相当于是连接
	 *
	 * @param dbName
	 * @return
	 */
	public DB getDB(String databaseName) throws Exception {
		if (mongo == null) {
			// 初始化
			mongo = init();
		}
		return mongo.getDB(databaseName);
	}

	public String getMongoConfigFileName() {
		return mongoConfigFileName;
	}

	public String getPictureDBName() {
		return pictureDBName;
	}

	/**
	 * 初始化连接池，设置参数。
	 */
	private MongoClient init() throws Exception {
		String confFileName = "connect.properties";
		MongoDBManager manager = SpringContextHolder.getBean(MongoDBManager.class);
		if (StringUtils.isNotEmpty(manager.getMongoConfigFileName())) {
			confFileName = manager.getMongoConfigFileName();
		}
		try {
			Properties properties = manager.loadProperties(confFileName);
			// 主机
			String host = properties.getProperty("mongodb.host");
			// 端口
			int port = Integer.parseInt(properties.getProperty("mongodb.port"));
			// 连接池的大小
			int poolSize = Integer.parseInt(properties.getProperty("mongodb.poolSize"));
			// 等待队列长度
			int blockSize = Integer.parseInt(properties.getProperty("mongodb.blockSize"));
			// 连接超时
			int connectTimeout = Integer.parseInt(properties.getProperty("mongodb.connectTimeout"));
			// 最大等待时间
			int maxWaitTime = Integer.parseInt(properties.getProperty("mongodb.maxWaitTime"));
			MongoClientOptions.Builder build = new MongoClientOptions.Builder();
			build.connectionsPerHost(poolSize); // 与目标数据库能够建立的最大connection数量为50
			build.autoConnectRetry(true); // 自动重连数据库启动
			build.threadsAllowedToBlockForConnectionMultiplier(blockSize); // 如果当前所有的connection都在使用中，则每个connection上可以有50个线程排队等待
			/*
			 * 一个线程访问数据库的时候，在成功获取到一个可用数据库连接之前的最长等待时间为2分钟
			 * 这里比较危险，如果超过maxWaitTime都没有获取到这个连接的话，该线程就会抛出Exception
			 * 故这里设置的maxWaitTime应该足够大，以免由于排队线程过多造成的数据库访问失败
			 */
			build.maxWaitTime(maxWaitTime);
			build.connectTimeout(connectTimeout); // 与数据库建立连接的timeout设置为1分钟
			// 其他参数根据实际情况进行添加
			MongoClientOptions opt = build.build();
			List<ServerAddress> seeds = new ArrayList<ServerAddress>();
			ServerAddress e = new ServerAddress(host, port);
			seeds.add(e);
			mongo = new MongoClient(seeds, opt);
			return mongo;
		} catch (MongoException e) {
			e.printStackTrace();
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	public static void initMongoDB() {
		logger.info("正在初始化MongoDBManager...");
		try {
			if (manager == null) {
				manager = SpringContextHolder.getBean(MongoDBManager.class);
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.info("正在初始化MongoDBManager失败...");
		}
		logger.info("正在初始化MongoDBManager完成...");
	}

	/**
	 * 载入多个ClassPath中的properties文件, 相同的属性将会覆盖之前的载入.
	 *
	 * @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
	 */
	public Properties loadProperties(String... locations) {
		Properties props = new Properties();
		for (String location : locations) {
			InputStream in = null;
			try {
				in = this.getClass().getResourceAsStream("/conf/" + location);
				propertiesPersister.load(props, new InputStreamReader(in, DEFAULT_ENCODING));
				logger.info("MongoDBManager配置文件加载成功...");
			} catch (IOException ex) {

			} finally {
				if (in != null) {
					try {
						in.close();
					} catch (IOException e) {
						logger.error("关闭输入流异常.", e);
					}
				}
			}
		}
		return props;
	}

	public void setAccessUrl(String accessUrl) {
		this.accessUrl = accessUrl;
	}

	public void setAttachmentDBName(String attachmentDBName) {
		this.attachmentDBName = attachmentDBName;
	}

	public void setMongoConfigFileName(String mongoConfigFileName) {
		this.mongoConfigFileName = mongoConfigFileName;
	}

	public void setPictureDBName(String pictureDBName) {
		this.pictureDBName = pictureDBName;
	}
}
